package com.cupdata.zicon.my.proxy;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

/**
 * 生成代理类
 */
public class Proxy {

    public static Object newInstance(ClassLoader classLoader, InvocationHandler invocationHandler, Class interfaceClass) {

        String proxyClassString = getProxyClassString(invocationHandler, invocationHandler.getObject().getClass().getMethods(),interfaceClass);
        File javaFile=new File("C:/demo/$Proxy1.java");
        try {
            FileOutputStream fos = new FileOutputStream(javaFile);
            fos.write(proxyClassString.getBytes());
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        int flag = compiler.run(null, null, null,"C:/demo/$Proxy1.java");
        Object o;
        try {
            URL[] urls = new URL[] { new URL("file:/" + "C:/demo/") };
            URLClassLoader loader = new URLClassLoader(urls);
            // 通过反射调用此类
            Class clazz = loader.loadClass("com.cupdata.zicon.my.proxy.$Proxy1");
            Constructor<?> constructor = clazz.getConstructor(interfaceClass, InvocationHandler.class);
            o = constructor.newInstance(invocationHandler.getObject(), invocationHandler);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("初始化异常!");
        }
        return o;
    }

    private static String getProxyClassString(InvocationHandler invocationHandler, Method[] methods, Class interfaceClass) {
        StringBuffer classHeader = new StringBuffer();
        Set<String> classUri = new HashSet<String>();
        classUri.add("com.cupdata.zicon.my.proxy.InvocationHandler;");
        classUri.add("java.lang.reflect.Method;");
        classUri.add(interfaceClass.getName() + ";");
        StringBuffer classBody = new StringBuffer();
        String separator = System.getProperty("line.separator");
        classHeader.append("package com.cupdata.zicon.my.proxy;").append(separator);
        classBody.append("public class $Proxy1 implements ").append(interfaceClass.getSimpleName()).append("{").append(separator)
                .append("private BizClass object;").append(separator)
                .append("private InvocationHandler invocationHandler;").append(separator)
                .append("public $Proxy1(BizClass object,InvocationHandler invocationHandler){").append(separator)
                .append("this.object=object;").append(separator)
                .append("this.invocationHandler=invocationHandler;}").append(separator);
        List<Method> methodList = Arrays.asList(Object.class.getMethods());
        for (Method method : methods) {
            if (methodList.contains(method)) {
                continue;
            }
            classUri.add(method.getReturnType().getName() + ";");
            String returnClassName = method.getReturnType().getSimpleName();
            List<String> paramNames = new ArrayList<String>();
            classBody.append("@Override").append(separator)
                    .append("public ").append(returnClassName).append(" ").append(method.getName()).append("(");
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes != null && parameterTypes.length > 0) {
                for (int i = 0; i < parameterTypes.length; i++) {
                    paramNames.add("a" + i);
                    classUri.add(parameterTypes[i].getName());
                    classBody.append(parameterTypes[i].getSimpleName()).append(" a").append(i).append(",");
                }
                classBody.setLength(classBody.length() - 1);
            }
            classBody.append("){").append(separator);
            classBody.append("Method method;").append(separator)
                    .append("Object invoke=null;").append(separator)
                    .append("try {").append(separator)
                    .append("method=BizClass.class.getMethod(\"").append(method.getName()).append("\");")
                    .append("invoke = invocationHandler.invoke(object, method,");
            if (paramNames != null && paramNames.size() > 0) {
                classBody.append("new Object[]{");
                for (String paramName : paramNames) {
                    classBody.append(paramName).append(",");
                }
                classBody.setLength(classBody.length() - 1);
                classBody.append("}");
            } else {
                classBody.append("null");
            }
            classBody.append(");").append(separator)
                    .append("} catch (Exception e) {").append(separator)
                    .append("e.printStackTrace();").append(separator)
                    .append("}").append(separator)
                    .append("return (").append(returnClassName).append(")").append("invoke;");
            classBody.append("}");
        }
        classBody.append("}");
        for (String s : classUri) {
            classHeader.append("import ").append(s).append(separator);
        }
        return classHeader.append(classBody).toString();
    }
}
